#include <stdio.h>
#include <string.h>

#include <ipms_api.h>

int PcdCount;
PCDInfo *PcdList;

int main(void)
{
    int idx, res;
    
    /* Initialize api */
    res = ipms_client_init_api();
    if (res == API_ERR_BAD_SOCKET) {
        printf("ERROR: Uanble to initialize socket\n");
        exit(1);
    }
    
    /* NOTE:
     * We ignore error checking in the following codes.
     * But remember to check it in the real world for error handling.
     */
    
    /* Connect to IMPS server */
    int ConnID;
    ConnID = ipms_client_connect("192.168.1.1", 1225);
    
    /* Register PCD nodes to server and get assigned PCD ID */
    int PcdID[4];
    PcdID[0] = ipms_client_register_pcd(ConnID, "11:22:33:44:55:66:77:88", "TV");
    PcdID[1] = ipms_client_register_pcd(ConnID, "01:02:03:04:05:06:07:08", "Home PC");
    PcdID[2] = ipms_client_register_pcd(ConnID, "0a:0b:0c:0d:0e:0f:01:02", "Printer");
    PcdID[3] = ipms_client_register_pcd(ConnID, "23:01:56:8d:e4:91:12:25", "WiFi AP");

    /* Get registered PCD list */
    res = ipms_client_get_pcd_list(ConnID, &PcdList, &PcdCount);
    printf("Total %d PCDs are registered!\n", PcdCount);
    /* Print all PCDs info */
    for (idx = 0; idx < PcdCount; idx++)
        printf("PCD ID:%d Description:%s\n", PcdList[idx]->ID, PcdList[idx]->Description);
    
    /* Get PCD#1 MAC from PCD#1 ID */
    char MAC_Str[24];
    res = ipms_client_get_pcd_mac(ConnID, PcdID[1], MAC_Str);
    if (strcmp(MAC_Str, "01:02:03:04:05:06:07:08") == 0)
        printf("[PCD#1] MAC Match\n");
    
    /* Get PCD#2 ID from PCD#2 MAC */
    int ID;
    res = ipms_client_get_pcd_id(ConnID, "0a:0b:0c:0d:0e:0f:01:02", &ID);
    if (ID == PcdID[2])
        printf("[PCD#2] ID Match\n");
    
    /* Get PCD#0 activation time */
    char ActTime[20];
    res = ipms_client_get_pcd_activate_time(ConnID, PcdID[0], ActTime);
    printf("[PCD#0] Activation time is %s\n", ActTime);
    
    /* Get PCD#3 full report */
    PCDReportData Report;
    res = ipms_client_get_report(ConnID, PcdID[3], &Report);
    printf("[PCD#3][%s] Voltage=%d Current=%d InstantEnergy=%d AccumulateEnergy=%d\n",
           Report.DateTime, Report.Voltage, Report.Current, Report.InstantEnergy, Report.AccumEnergy);
    
    /* Individually get voltage/current/energy reports */
    int Volt, Curr, InstEnergy, AccumEnergy;
    Volt = ipms_client_get_report_voltage(ConnID, PcdID[0]);
    printf("[PCD#0] Voltage=%d\n", Volt);
    Curr = ipms_client_get_report_current(ConnID, PcdID[1]);
    printf("[PCD#1] Current=%d\n", Curr);
    InstEnergy = ipms_client_get_report_instant_energy(ConnID, PcdID[2]);
    printf("[PCD#2] InstantEnergy=%d\n", InstEnergy);
    AccumEnergy = ipms_client_get_report_accum_energy(ConnID, PcdID[3]);
    printf("[PCD#3] AccumulateEnergy=%d\n", AccumEnergy);
    
    /* Set PCD ON/OFF state */
    /* Set PCD#0 ON immediately */
    res = ipms_client_control(ConnID, PcdID[0], API_CTRL_TYPE_ONOFF, 1, 0);
    /* Set PCD#1 OFF after a 1 sec timeout */
    res = ipms_client_control(ConnID, PcdID[1], API_CTRL_TYPE_ONOFF, 0, 10);
    
    /* Get PCD ON/OFF status */
    PCDStatus PCDStat;
    res = ipms_client_get_status(ConnID, PcdID[1], &PCDStat);
    /* Please refer to API Spec for the status bit configuration */
    if (PCDStat.Status == 0)
        printf("[PCD#1] Current status is OFF\n");
    else if (PCDStat.Status == 1)
        printf("[PCD#1] Current status is ON, and is going to be OFF after %d miniseconds\n", PCDStat.TimeLeft * 100);
    else if (PCDStat.Status == 2)
        printf("[PCD#1] Current status is OFF, and is going to be ON after %d miniseconds\n", PCDStat.TimeLeft * 100);
    else if (PCDStat.Status == 3)
        printf("[PCD#1] Current status is ON\n");
    
    /* Install an event handler to deal with PCD status change */
    ipms_client_install_event_handler(ConnID, PcdID[0], API_EVENT_STAT_CHANGE, &StatChangeHandler, NULL);
    ipms_client_install_event_handler(ConnID, PcdID[1], API_EVENT_STAT_CHANGE, &StatChangeHandler, NULL);
    ipms_client_install_event_handler(ConnID, PcdID[2], API_EVENT_STAT_CHANGE, &StatChangeHandler, NULL);
    ipms_client_install_event_handler(ConnID, PcdID[3], API_EVENT_STAT_CHANGE, &StatChangeHandler, NULL);
    
    /* Install an event handler to deal with PCD auto report */
    PCDReportData Report0, Report1, Report2, Report3; /* NOTE: Should be defined as global variable */
    ipms_client_install_event_handler(ConnID, PcdID[0], API_EVENT_AUTO_REPORT , &AutoReportHandler, (void *)&Report0);
    ipms_client_install_event_handler(ConnID, PcdID[1], API_EVENT_AUTO_REPORT , &AutoReportHandler, (void *)&Report1);
    ipms_client_install_event_handler(ConnID, PcdID[2], API_EVENT_AUTO_REPORT , &AutoReportHandler, (void *)&Report2);
    ipms_client_install_event_handler(ConnID, PcdID[3], API_EVENT_AUTO_REPORT , &AutoReportHandler, (void *)&Report3);
    
    /* Start auto report */
    res = ipms_client_start_auto_report(ConnID, PcdID[0], API_REPORT_SEL_ALL);
    /* Only instantaneous energy is selected for report */
    res = ipms_client_start_auto_report(ConnID, PcdID[1], API_REPORT_SEL_INST_ENERG);
    /* Only voltage and current are selected for report */
    res = ipms_client_start_auto_report(ConnID, PcdID[2], API_REPORT_SEL_VOLT | API_REPORT_SEL_CURR);
    /* Only voltage and accumulated energy are selected for report */
    res = ipms_client_start_auto_report(ConnID, PcdID[3], API_REPORT_SEL_VOLT | API_REPORT_SEL_ACCUM_ENERG);
    
    
    /* Do something you want ... */
    
    
    /* Stop auto report */
    res = ipms_client_stop_auto_report(ConnID, PcdID[0]);
    res = ipms_client_stop_auto_report(ConnID, PcdID[1]);
    res = ipms_client_stop_auto_report(ConnID, PcdID[2]);
    res = ipms_client_stop_auto_report(ConnID, PcdID[3]);
    
    /* Unregister PCDs from IPMS server */
    res = ipms_client_unregister_pcd(ConnID, PcdID[0]);
    res = ipms_client_unregister_pcd(ConnID, PcdID[1]);
    res = ipms_client_unregister_pcd(ConnID, PcdID[2]);
    res = ipms_client_unregister_pcd(ConnID, PcdID[3]);
    
    /* Disconnect from IPMS server */
    res = ipms_client_disconnect(ConnID);
    
    return 0;
}

void StatChangeHandler(int conn_id, int pcd_id, void *arg)
{
    PCDStatus stat;
    
    res = ipms_client_get_status(conn_id, pcd_id, &stat);
    if (stat.Status == 0)
        printf("PCD#%d is currently OFF\n", pcd_id);
    else if (stat.Status == 3)
        printf("PCD#%d is currently ON\n", pcd_id);
}

void AutoReportHandler(int conn_id, int pcd_id, void *arg)
{
    PCDReportData *report = (PCDReportData *)arg;
    
    printf("[PCD#%d][AutoReport][%s] Voltage=%d Current=%d InstantEnergy=%d AccumulateEnergy=%d\n",
           pcd_id, report.DateTime, report.Voltage, report.Current, report.InstantEnergy, report.AccumEnergy);
    
    /* Pseudo call to update your own database for analysis */
    UpdateDatabase(pcd_id, report);
}
